from django.conf import settings
from django.shortcuts import render
from django.views import View
from django.http import JsonResponse
# Create your views here.
from itsdangerous import TimedJSONWebSignatureSerializer

from apps.goods.models import SKU
from apps.user1.models import User
import json
import re
from django_redis import get_redis_connection
# 导入login方法
from django.contrib.auth import login,logout
from django.contrib.auth import authenticate
from celery_tasks.emails.tasks import send_emails
from apps.carts.utils import megre_cart


class UsernameCountView(View):
    def get(self,request,username):
        count =  User.objects.filter(username=username).count()
        return JsonResponse({'count':count})


class MobileCountView(View):
    def get(self,request,mobile):
        count =  User.objects.filter(mobile=mobile).count()
        return JsonResponse({'count':count})


class RegisterView(View):
    def post(self,request):
        # 1、接受前端传递的json数据
        json_data = request.body.decode()
        # 2、将json转化字典数据
        dict_data = json.loads(json_data)
        # 3、从字典中提取相关的字段数据
        username = dict_data.get('username')
        mobile = dict_data.get('mobile')
        password = dict_data.get('password')
        password2 = dict_data.get('password2')
        sms_code = dict_data.get('sms_code')
        allow = dict_data.get('allow')
        # 4、验证字段数据
        # 4-1、验证数据完整性all方法中如果有空值会返回false
        if not all([username, mobile, password, password2, sms_code, allow]):
            return JsonResponse({'code': 400, 'errmsg': '参数不完整'}, status=400)
        # 4-2、判断用户名格式
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400, 'errmsg': '用户名格式不正确'}, status=400)
        # 4-3、判断手机号格式
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '手机号格式不正确'}, status=400)
        # 4-4、判断密码格式
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': '密码格式不正确'}, status=400)
        # 4-5、判断两次是否一致
        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '密码不一致'}, status=400)
        # 4-6、判断是否同意协议
        if allow != True:
            return JsonResponse({'code': 400, 'errmsg': '未同意协议'}, status=400)
        # 4-7、短信验证判断
        conn = get_redis_connection('verify')
        real_code = conn.get('sms_code_%s' % mobile)
        # 判断real_code是否超过有效期
        if real_code is None:
            return JsonResponse({'code': 400, 'errmsg': '验证码失效'}, status=400)
        if sms_code != real_code.decode():
            return JsonResponse({'code': 400, 'errmsg': '短信验证码不一致'}, status=400)
        # 5、将数据保存在数据库中
        user = User.objects.create_user(username=username,password=password,mobile=mobile)
        # 用户注册成功则需要进行状态保持
        login(request, user)
        # 6、返回结果
        return JsonResponse({'code':0,'errmsg':'ok'})


class LoginView(View):
    def post(self,request):
        # 1、获取前端传递的用户数据,是json格式,类型是bytes
        json_data = request.body.decode()
        # 2、将json数据转化为字典数据
        dict_data = json.loads(json_data)
        # 3、从字典中提取用户名字段数据，密码字段数据，记住密码状态数据
        username = dict_data.get('username')
        password = dict_data.get('password')
        remembered = dict_data.get('remembered')
        # 4、验证数据
        # 4-1 验证数据完整性
        if not all([username, password]):
            return JsonResponse({'code': 400, 'errmsg': '参数缺失'}, status=400)
        # 4-2 验证用户名是否存在
        # try:
        #     user = User.objects.get(username=username)
        # except:
        #     return JsonResponse({'code': 400, 'errmsg': '用户不存在'}, status=400)
        # 4-3 验证密码
        # if not user.check_password(password):
        #     return JsonResponse({'code': 400, 'errmsg': '密码不正确'}, status=400)
        user = authenticate(request, username=username, password=password)

        # 判断是否为空,如果为空,返回
        if not user:
            return JsonResponse({'code': 400, 'errmsg': '用户名或者密码错误'})
        # 5、数据验证没有问题，用户存在则登录成功进行状态保持
        login(request,user)
        # 6、返回结果，返回时根据记住密码状态数据，进行session数据的有效期设置
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        if remembered:
            # 记住密码，设置session有效期为两周
            request.session.set_expiry(None)
            response.set_cookie('username',user.username,max_age=60*60*24*14)
        if not remembered:
            request.session.set_expiry(0)
            response.set_cookie('username',user.username)

            # 合并购物车，业务可以封装成方法进行调用
            response = megre_cart(request, response, user)

        return response


class LogoutView(View):
    def delete(self, request):
        # 1、使用Django的logout方法实现退出登录，主要对session数据操作flush清空
        logout(request)
        # 2、在登录时写入用户的cookie数据，所有退出登录时需要删除cookie的用户名
        resposne = JsonResponse({'code': 0, 'errmsg': 'ok'})
        resposne.delete_cookie('username')
        # 3、返回结果
        return resposne


class UserInfoView(View):
    """
            用户中心
            1、进入用户中心必须返回相应用户数据
            2、要有用户数据，就必须要求用户登录，可以通过request.user获取登录用户信息
            3、要求用户登录则必须先判断用户是否登录过，is_authenticated可以判断
        """

    def get(self, request):
        # 如果用户登录过，则会获取用户信息
        user = request.user
        # is_authenticated判断用户是否登录过，如果登录过则返回ture，否则返回false
        if not user.is_authenticated:
            # 用户未登录
            return JsonResponse({'code': 400, 'errmsg': '用户未登录'})

        # 用户返回结果时，必须有用户数据，则进入用户中心获取用户数据时，必须处于登录状态，否则无法返回用户数据
        return JsonResponse({'code': 0, 'errmsg': 'ok', "info_data": {
            "username": user.username,
            "mobile": user.mobile,
            "email": user.email,
            "email_active": user.email_active
        }})


class UserEmailView(View):
    def put(self, request):
        # 1、获取前端传递的邮箱数据，json
        json_data = request.body.decode()
        dict_data = json.loads(json_data)
        email = dict_data.get('email')
        # 2、验证邮箱格式
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 0, 'errmsg': "邮箱格式不正确"})
        # 3、更新邮箱
        # 知道更新哪个用户的邮箱，需要获取用户
        # 用户登陆过才能进行更新
        user = request.user
        # is_authenticated判断用户是否登录过，如果登录过则返回ture，否则返回false
        if not user.is_authenticated:
            # 用户未登录
            return JsonResponse({'code': 400, 'errmsg': '用户未登录'})

        # 获取到登录用户后更新email字段
        user.email = email
        # 如果没有save则无法更新
        user.save()
        # 4、给邮箱发送信息进行验证邮箱的真实性
        # 生成一个加密的用户信息
        tjs = TimedJSONWebSignatureSerializer(settings.SECRET_KEY, 300)
        token = tjs.dumps({'username': user.username, 'email': email}).decode()

        # 验证信息
        html_messages = 'http://www.meiduo.site:8080/success_verify_email.html?token=' + token
        send_emails.delay(email,html_messages)
        return JsonResponse({'code':0,'errmsg':'ok'})


class UserEmailVerifyView(View):
    def put(self,request):
        # 1、获取加密的用户信息，在查询字符串中携带
        token = request.GET.get('token')
        # 2、解密数据
        tjs = TimedJSONWebSignatureSerializer(settings.SECRET_KEY, 300)
        try:
            data_dict = tjs.loads(token)
        except:
            return JsonResponse({'code': 400, 'message': '数据错误'}, status=400)
        # 3、提取用户数据
        username = data_dict.get('username')
        email = data_dict.get('email')
        # 4、验证用户数据
        try:
            user = User.objects.get(username=username, email=email)
        except:
            # 说名用户数据不存在，验证失败
            return JsonResponse({'code': 400, 'message': '  验证失败'}, status=400)
        # 5、验证成功则修改邮箱验证状态
        user.email_active = True
        user.save()
        # 6、返回结果
        return JsonResponse({'code':0,'errmsg':'ok'})


# 用户商品浏览记录
class UserHistoryView(View):
    # 保存用户浏览记录
    def post(self,request):
        # 1、获取商品id
        data_json = request.body.decode()
        data_dict = json.loads(data_json)
        sku_id = data_dict.get('sku_id')
        # 2、验证商品id对应商品是否存在
        try:
            sku = SKU.objects.get(id=sku_id)
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 3、将商品id保存在redis的列表中
        # 数据需要去重。避免用户重复访问同一个商品造成数据的重复存储
        # 3-1 连接redis
        conn = get_redis_connection('history')
        # 3-2 数据需要去重。避免用户重复访问同一个商品造成数据的重复存储
        # redis的key需要是唯一的，用户是唯一的，在记录商品浏览信息时，用户是处于登录状态。request.user获取登录后的用户
        conn.lrem('history_%d' % request.user.id, 0, sku_id)
        # 写入数据
        conn.lpush('history_%d' % request.user.id, sku_id)
        # 控制浏览商品的存储数量。避免用户访问很多商品后展示浏览信息不方便，最近浏览的商品展示保留5个数据即可
        conn.ltrim('history_%d' % request.user.id, 0, 5)

        return JsonResponse({'code': 0, 'errmsg': 'ok'})

    # 获取用户浏览记录
    def get(self,request):
        # 获取用户id，在redis是以用户id为key
        id = request.user.id
        # 连接redis
        conn = get_redis_connection('history')
        # 获取用户的浏览商品id
        sku_ids = conn.lrange('history_%d' % id,0,10)
        # 根据商品id查询sku表获取商品数据对象，范围查询
        skus = SKU.objects.filter(id__in=sku_ids)
        # 构造响应数据
        sku_list=[]
        for sku in skus:
            sku_list.append({
                'id':sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'skus': sku_list
        })
